package com.isyscore.os.core.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.ImmutableMap;
import com.isyscore.boot.login.LoginUserManager;
import com.isyscore.device.common.model.RespDTO;
import com.isyscore.device.common.util.JsonMapper;
import com.isyscore.os.core.entity.LicenseNotifyDTO;
import com.isyscore.os.core.exception.DataFactoryException;
import com.isyscore.os.core.exception.ErrorCode;
import com.isyscore.os.core.exception.ErrorGroup;
import com.isyscore.os.core.license.LicenseEvent;
import com.isyscore.os.core.model.dto.ErrorCodeInfoDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用于运维的健康检查
 *
 * @author felixu
 * @since 2021.05.10
 */
@RestController
@Api(tags = "应用信息")
@RequiredArgsConstructor
@RequestMapping("${api-full-prefix:}/system")
@Slf4j
public class LifecycleController {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    @Value("${pom.version}")
    private String version;
    private final static String LICENSE_SIGN_GLOBAL_KEY="--1sysL1c--";

    private final MessageSource messageSource;
    private final LoginUserManager loginUserManager;

    @ApiOperation("查询应用程序运行状态")
    @GetMapping("/status")
    public Map<String,String> status() {
        return ImmutableMap.of("version",version);
    }

    @GetMapping("/error/desc")
    @ApiOperation("获取所有 ErrorCode 对应的信息")
    public List<ErrorCodeInfoDTO> errorCode() {
        Map<ErrorGroup, List<ErrorCodeInfoDTO.ErrorInfo>> errorMap = Arrays.stream(ErrorCode.values()).parallel()
                .map(error -> new ErrorCodeInfoDTO.ErrorInfo(error.getCode(), messageSource.getMessage(error.getMessage(),
                        null, error.getMessage(), LocaleContextHolder.getLocale()), error.name(), error.getGroup()))
                .collect(Collectors.groupingBy(ErrorCodeInfoDTO.ErrorInfo::getGroup));
        return Arrays.stream(ErrorGroup.values())
                .filter(ErrorGroup::isAccessible)
                .map(group -> {
                    List<ErrorCodeInfoDTO.ErrorInfo> infos = errorMap.get(group);
                    if (CollectionUtils.isEmpty(infos))
                        return null;
                    infos.sort(Comparator.comparingInt(ErrorCodeInfoDTO.ErrorInfo::getCode));
                    return new ErrorCodeInfoDTO(group.getDesc(), infos);
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    @GetMapping("version")
    @ApiOperation("系统版本")
    public RespDTO<String> version() {
        return RespDTO.onSuc(version);
    }
    @PostMapping("/license/notify")
    @ApiOperation("授权通知")
    public Map<String,Integer> licenseNotify(@RequestBody LicenseNotifyDTO licenseNotify) {
        log.info("收到license变更{}", JsonMapper.toAlwaysJson(licenseNotify));
        String realSign= DigestUtils.md5Hex(new StringBuffer()
                .append(licenseNotify.getLicensed())
                .append(licenseNotify.getExpire())
                .append(LICENSE_SIGN_GLOBAL_KEY)
                .append(licenseNotify.getTimestamp()).toString());
        if(!StrUtil.equals(realSign,licenseNotify.getSign())){
            throw new DataFactoryException(ErrorCode.ERROR_SIGN,licenseNotify.getSign());
        }
        if (CollUtil.isNotEmpty(licenseNotify.getData())){
            LicenseEvent licenseEvent=new LicenseEvent(this,licenseNotify.getData());
            applicationEventPublisher.publishEvent(licenseEvent);
        }
        return ImmutableMap.of("code", 0);
    }

}
